package com.geoai.basiclib.ext

import android.animation.Animator
import android.animation.IntEvaluator
import android.animation.ValueAnimator
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Color
import android.view.ViewGroup
import com.geoai.basiclib.R
import android.content.DialogInterface
import android.content.res.ColorStateList
import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.Drawable
import android.graphics.drawable.LayerDrawable
import android.view.View
import android.widget.ImageView
import android.widget.TextView
import android.widget.Toast
import androidx.annotation.*
import androidx.appcompat.app.AlertDialog
import androidx.recyclerview.widget.RecyclerView

/**
 * View相关

view.width(100)           // 设置View的宽度为100
view.widthAndHeight(100)  // 改变View的宽度和高度为100
view.animateWidthAndHeight(600,900) //带有动画
view.animateWidth(600,900, action = { //监听动画进度，执行可选操作 }) //带有动画
view.margin(leftMargin = 100)  // 设置View左边距为100
view.click { toast("aa") }    // 设置点击监听，已实现事件节流，350毫秒内只能点击一次
view.longClick {             // 设置长按监听
toast("long click")
true
}
view.gone()
view.visible()
view.invisible()
view.isGone  // 属性
view.isVisible // 属性
view.isInvisible // 属性
view.toggleVisibility() // 切换可见性
view.toBitmap()           // 获取View的截图，支持RecyclerView长列表截图
// 遍历子View
layout.children.forEachIndexed { index, view ->

}
 */

/**
 * 设置View的高度
 */
fun View.height(height: Int): View {
    val params = layoutParams ?: ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
            ViewGroup.LayoutParams.WRAP_CONTENT)
    params.height = height
    layoutParams = params
    return this
}

/**
 * 设置View高度，限制在min和max范围之内
 * @param h
 * @param min 最小高度
 * @param max 最大高度
 */
fun View.limitHeight(h: Int, min: Int, max: Int): View {
    val params = layoutParams ?: ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
            ViewGroup.LayoutParams.WRAP_CONTENT)
    when {
        h < min -> params.height = min
        h > max -> params.height = max
        else -> params.height = h
    }
    layoutParams = params
    return this
}

/**
 * 设置View的宽度
 */
fun View.width(width: Int): View {
    val params = layoutParams ?: ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
            ViewGroup.LayoutParams.WRAP_CONTENT)
    params.width = width
    layoutParams = params
    return this
}

/**
 * 设置View宽度，限制在min和max范围之内
 * @param w
 * @param min 最小宽度
 * @param max 最大宽度
 */
fun View.limitWidth(w: Int, min: Int, max: Int): View {
    val params = layoutParams ?: ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
            ViewGroup.LayoutParams.WRAP_CONTENT)
    when {
        w < min -> params.width = min
        w > max -> params.width = max
        else -> params.width = w
    }
    layoutParams = params
    return this
}

/**
 * 设置View的宽度和高度
 * @param width 要设置的宽度
 * @param height 要设置的高度
 */
fun View.widthAndHeight(width: Int, height: Int): View {
    val params = layoutParams ?: ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
            ViewGroup.LayoutParams.WRAP_CONTENT)
    params.width = width
    params.height = height
    layoutParams = params
    return this
}

/**
 * 设置View的margin
 * @param leftMargin 默认保留原来的
 * @param topMargin 默认是保留原来的
 * @param rightMargin 默认是保留原来的
 * @param bottomMargin 默认是保留原来的
 */
fun View.margin(leftMargin: Int = Int.MAX_VALUE, topMargin: Int = Int.MAX_VALUE, rightMargin: Int = Int.MAX_VALUE, bottomMargin: Int = Int.MAX_VALUE): View {
    val params = layoutParams as ViewGroup.MarginLayoutParams
    if (leftMargin != Int.MAX_VALUE)
        params.leftMargin = leftMargin
    if (topMargin != Int.MAX_VALUE)
        params.topMargin = topMargin
    if (rightMargin != Int.MAX_VALUE)
        params.rightMargin = rightMargin
    if (bottomMargin != Int.MAX_VALUE)
        params.bottomMargin = bottomMargin
    layoutParams = params
    return this
}

/**
 * 设置宽度，带有过渡动画
 * @param targetValue 目标宽度
 * @param duration 时长
 * @param action 可选行为
 */
fun View.animateWidth(targetValue: Int, duration: Long = 400, listener: Animator.AnimatorListener? = null,
                      action: ((Float) -> Unit)? = null) {
    post {
        ValueAnimator.ofInt(width, targetValue).apply {
            addUpdateListener {
                width(it.animatedValue as Int)
                action?.invoke((it.animatedFraction))
            }
            if(listener!=null)addListener(listener)
            setDuration(duration)
            start()
        }
    }
}

/**
 * 设置高度，带有过渡动画
 * @param targetValue 目标高度
 * @param duration 时长
 * @param action 可选行为
 */
fun View.animateHeight(targetValue: Int, duration: Long = 400, listener: Animator.AnimatorListener? = null, action: ((Float) -> Unit)? = null) {
    post {
        ValueAnimator.ofInt(height, targetValue).apply {
            addUpdateListener {
                height(it.animatedValue as Int)
                action?.invoke((it.animatedFraction))
            }
            if(listener!=null)addListener(listener)
            setDuration(duration)
            start()
        }
    }
}

/**
 * 设置宽度和高度，带有过渡动画
 * @param targetWidth 目标宽度
 * @param targetHeight 目标高度
 * @param duration 时长
 * @param action 可选行为
 */
fun View.animateWidthAndHeight(targetWidth: Int, targetHeight: Int, duration: Long = 400, listener: Animator.AnimatorListener? = null, action: ((Float) -> Unit)? = null) {
    post {
        val startHeight = height
        val evaluator = IntEvaluator()
        ValueAnimator.ofInt(width, targetWidth).apply {
            addUpdateListener {
                widthAndHeight(it.animatedValue as Int, evaluator.evaluate(it.animatedFraction, startHeight, targetHeight))
                action?.invoke((it.animatedFraction))
            }
            if(listener!=null)addListener(listener)
            setDuration(duration)
            start()
        }
    }
}

/**
 * 设置点击监听, 并实现事件节流
 */
var _viewClickFlag = false
var _clickRunnable = Runnable { _viewClickFlag = false }
fun View.click(action: (view: View) -> Unit) {
    setOnClickListener {
        if (!_viewClickFlag) {
            _viewClickFlag = true
            action(it)
        }
        removeCallbacks(_clickRunnable)
        postDelayed(_clickRunnable, 350)
    }
}

/**
 * 设置长按监听
 */
fun View.longClick(action: (view: View) -> Boolean) {
    setOnLongClickListener {
        action(it)
    }
}


/*** 可见性相关 ****/
fun View.gone() {
    visibility = View.GONE
}

fun View.visible() {
    visibility = View.VISIBLE
}

fun View.invisible() {
    visibility = View.INVISIBLE
}

val View.isGone: Boolean
    get() {
        return visibility == View.GONE
    }

val View.isVisible: Boolean
    get() {
        return visibility == View.VISIBLE
    }

val View.isInvisible: Boolean
    get() {
        return visibility == View.INVISIBLE
    }

/**
 * 获取View的截图, 支持获取整个RecyclerView列表的长截图
 * 注意：调用该方法时，请确保View已经测量完毕，如果宽高为0，则将抛出异常
 */
fun View.toBitmap(): Bitmap {
    if (measuredWidth == 0 || measuredHeight == 0) {
        throw RuntimeException("调用该方法时，请确保View已经测量完毕，如果宽高为0，则抛出异常以提醒！")
    }
    return when (this) {
        is RecyclerView -> {
            this.scrollToPosition(0)
            this.measure(View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY),
                    View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED))

            val bmp = Bitmap.createBitmap(width, measuredHeight, Bitmap.Config.ARGB_8888)
            val canvas = Canvas(bmp)

            //draw default bg, otherwise will be black
            if (background != null) {
                background.setBounds(0, 0, width, measuredHeight)
                background.draw(canvas)
            } else {
                canvas.drawColor(Color.WHITE)
            }
            this.draw(canvas)
            //恢复高度
            this.measure(View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY),
                    View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.AT_MOST))
            bmp //return
        }
        else -> {
            val screenshot = Bitmap.createBitmap(measuredWidth, measuredHeight, Bitmap.Config.ARGB_8888)
            val canvas = Canvas(screenshot)
            if (background != null) {
                background.setBounds(0, 0, width, measuredHeight)
                background.draw(canvas)
            } else {
                canvas.drawColor(Color.WHITE)
            }
            draw(canvas)// 将 view 画到画布上
            screenshot //return
        }
    }

}


// 所有子View
inline val ViewGroup.children
    get() = (0 until childCount).map { getChildAt(it) }

/**
 * Get the [String] for the given [stringRes].
 */
fun View.getString(@StringRes stringRes: Int): String = context.resources.getString(stringRes)

/**
 * Get the [Drawable] for the given [drawableRes].
 */
fun View.getDrawable(@DrawableRes drawableRes: Int): Drawable = context.resources.getDrawable(drawableRes)

/**
 * The the color int for the given [colorRes].
 */
@ColorInt
fun View.getColor(@ColorRes colorRes: Int): Int = context.resources.getColor(colorRes)

/**
 * The the px size for the given [dimenRes].
 */
@Px
fun View.getDimension(@DimenRes dimenRes: Int): Float = context.resources.getDimension(dimenRes)

/**
 * Set the view [View.VISIBLE].
 */
fun View.show() {
    visibility = View.VISIBLE
}

/**
 * Set the view [View.GONE].
 */
fun View.hide() {
    visibility = View.GONE
}

/**
 * Toggle the view between [View.GONE] and [View.VISIBLE]
 */
fun View.toggleVisibility() {
    if (visibility == View.VISIBLE) hide()
    else show()
}

/**
 * Show a short length toast with the given [messageResId].
 */
fun View.showShortToast(@StringRes messageResId: Int) {
    Toast.makeText(
        context,
        messageResId,
        Toast.LENGTH_SHORT)
        .show()
}

/**
 * Show a long length toast with the given [messageResId].
 */
fun View.showLongToast(@StringRes messageResId: Int) {
    Toast.makeText(
        context,
        messageResId,
        Toast.LENGTH_LONG)
        .show()
}

/**
 * Show a short length toast with the given [String].
 */
fun View.showShortToast(message: String?) {
    Toast.makeText(
        context,
        message,
        Toast.LENGTH_SHORT)
        .show()
}

/**
 * Show a long length toast with the given [String].
 */
fun View.showLongToast(message: String?) {
    Toast.makeText(
        context,
        message,
        Toast.LENGTH_LONG)
        .show()
}

/**
 * The [TextView]'s text color int.
 */
var TextView.textColor: Int
    @ColorInt
    get() = this.currentTextColor
    set(@ColorInt value) {
        this.setTextColor(value)
    }

/**
 * The [TextView]'s text color state list.
 */
var TextView.textColorStateList: ColorStateList?
    get() = this.textColors
    set(value) {
        this.setTextColor(value)
    }

/**
 * The [ImageView]'s drawable.
 */
var ImageView.imageDrawable: Drawable?
    get() = this.drawable
    set(value) {
        this.setImageDrawable(value)
    }

/**
 * Show an alert dialog.
 * @param dialogTheme The style of the dialog
 * @param isCancellable Dismiss the dialog when touch outside its bounds
 * @param title Dialog title text
 * @param icon  Dialog title icon
 * @param message Dialog message
 * @param dismissButton Dismiss button text
 * @param dialogClickListener
 */
fun View.showAlertDialog(@StyleRes dialogTheme: Int = R.style.Theme_normal_dialog,
                         isCancellable: Boolean = true,
                         title: String? = getString(R.string.alert),
                         icon: Drawable? = null,
                         message: String? = null,
                         dismissButton: String? = getString(R.string.ok),
                         dialogClickListener: DialogInterface.OnClickListener? = null,
                         dialogDismissListener: DialogInterface.OnDismissListener? = null) {
    val builder = AlertDialog.Builder(context, dialogTheme)
    builder.setTitle(title)
    builder.setIcon(icon)
    builder.setCancelable(isCancellable)
    builder.setMessage(message)
    builder.setPositiveButton(dismissButton, dialogClickListener)
    builder.setOnDismissListener(dialogDismissListener)
    val dialog = builder.create()
    dialog.show()
}

/**
 * Show an alert dialog.
 * @param dialogTheme The style of the dialog
 * @param isCancellable Dismiss the dialog when touch outside its bounds
 * @param title Dialog title text
 * @param icon  Dialog title icon
 * @param message Dialog message
 * @param positiveButton Positive button text
 * @param negativeButton Negative button text
 * @param dialogClickListener
 */
fun View.showConfirmationDialog(@StyleRes dialogTheme: Int = R.style.Theme_normal_dialog,
                                isCancellable: Boolean = true,
                                title: String? = getString(R.string.alert),
                                icon: Drawable? = null,
                                message: String? = null,
                                positiveButton: String? = getString(R.string.ok),
                                negativeButton: String? = getString(R.string.cancel),
                                dialogClickListener: DialogInterface.OnClickListener? = null,
                                dialogDismissListener: DialogInterface.OnDismissListener? = null) {
    val builder = AlertDialog.Builder(context, dialogTheme)
    builder.setIcon(icon)
    builder.setTitle(title)
    builder.setCancelable(isCancellable)
    builder.setMessage(message)
    builder.setPositiveButton(positiveButton, dialogClickListener)
    builder.setNegativeButton(negativeButton, dialogClickListener)
    builder.setOnDismissListener(dialogDismissListener)
    val dialog = builder.create()
    dialog.show()
}

/**
 * Set the border to a view.
 * The extension creates a layered background which can be used to set up a border to the view.
 *
 * @param backgroundColor - The color for the solid background.
 * @param borderColor - The color for the border for the view.
 * @param leftBorder - The size of the left border.
 * @param topBorder - The size of the top border.
 * @param rightBorder - The size of the right border.
 * @param bottomBorder - The size of the bottom border.
 *
 */
fun View.setBorder(@ColorInt backgroundColor: Int = getColor(R.color.transparent),
                   @ColorInt borderColor: Int = getColor(R.color.transparent),
                   leftBorder: Int = 0,
                   topBorder: Int = 0,
                   rightBorder: Int = 0,
                   bottomBorder: Int = 0) {
    val borderColorDrawable = ColorDrawable(borderColor)
    val backgroundColorDrawable = ColorDrawable(backgroundColor)

    // Initialize a new array of drawable objects
    val drawables = arrayOf<Drawable>(borderColorDrawable, backgroundColorDrawable)

    // Initialize a new layer drawable instance from drawables array
    val layerDrawable = LayerDrawable(drawables)

    // Set padding for background color layer
    layerDrawable.setLayerInset(
        1,  // Index of the drawable to adjust [background color layer]
        leftBorder,  // Number of pixels to add to the left bound [left border]
        topBorder,  // Number of pixels to add to the top bound [top border]
        rightBorder,  // Number of pixels to add to the right bound [right border]
        bottomBorder // Number of pixels to add to the bottom bound [bottom border]
    )
    this.background = layerDrawable

}

/**
 * On click listener for recycler view.
 */
fun <T : RecyclerView.ViewHolder> T.listen(event: (position: Int) -> Unit): T {
    itemView.setOnClickListener {
        event.invoke(adapterPosition)
    }
    return this
}
